package service

import (
	"context"
	"errors"
	"fmt"
	"strconv"

	"bmember/internal/object"

	pb "bmember/api/pb/server"
	"bmember/internal/dao"
	"bmember/internal/model"
	"bmember/pkg/lueerror"
	"bmember/pkg/util"
)

func (srv *assetSrv) toRechargeOrderReply(order *model.RechargeOrder) *pb.RechargeOrderReply {
	if order == nil {
		return nil
	}
	return &pb.RechargeOrderReply{
		BrandId:       order.BrandId,
		StoreId:       order.StoreId,
		MemberId:      order.MemberId,
		AccId:         order.AccId,
		OrderNo:       order.OrderNo,
		Amount:        order.Amount,
		RefundAmount:  order.RefundAmount,
		PayOrderNo:    order.PayOrderNo,
		RefundOrderNo: order.RefundOrderNo,
		PayedTime:     util.TimeStdFormat(order.PayedTime),
		RefundedTime:  util.TimeStdFormat(order.RefundedTime),
		Status:        order.GetStatus(),
		CreatedAt:     util.TimeStdFormat(order.CreatedAt),
	}
}

// CreateRechargeOrder 创建充值订单
func (srv *assetSrv) CreateRechargeOrder(ctx context.Context, memberId int64, p *pb.CreateRechargeOrderReq, biliApp string) (*pb.RechargeOrderReply, lueerror.LueError) {
	if p == nil {
		return nil, nil
	}
	// 检查账号是否存在
	acc, errL := srv.getAccountById(ctx, memberId, p.AccId, false)
	if errL != nil {
		return nil, errL
	}
	// 检查卡设置
	card, errL := srv.getCardInfo(ctx, acc.CardId)
	if errL != nil {
		return nil, errL
	}
	// 门店是否使用
	if !card.Group.CanUseInStore(p.StoreId) {
		return nil, lueerror.StoreNotAllowed(fmt.Errorf("门店 %d 在体系 %d 不适用", p.StoreId, acc.GroupId))
	}
	// 是否允许充值
	if !card.Card.CanRecharge {
		return nil, lueerror.RechargeForbidden(fmt.Errorf("卡 %d 不允许充值", acc.CardId))
	}
	// 充值金额检查
	if !card.Card.IsValidAmount(p.Amount) {
		return nil, lueerror.TopupLimit(fmt.Errorf("充值 %d 金额过低", p.Amount))
	}
	var err error
	order := model.NewRechargeOrder(acc.BrandId, p.StoreId, acc.GroupId, acc.CardId, acc.MemberId, acc.Id, p.Amount, biliApp)
	order.Id, err = dao.GetOrdersDao().CreateRechargeOrder(ctx, order)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return srv.toRechargeOrderReply(order), nil
}

func (srv *assetSrv) getRechargeOrderByOrderNo(ctx context.Context, memberId int64, orderNo string, canNull, isLock bool) (*model.RechargeOrder, lueerror.LueError) {
	var err error
	var order *model.RechargeOrder
	if isLock {
		order, err = dao.GetOrdersDao().LockRechargeOrderByOrderNo(ctx, orderNo)
	} else {
		order, err = dao.GetOrdersDao().GetRechargeOrderByOrderNo(ctx, orderNo)
	}
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if order == nil && !canNull {
		return nil, lueerror.OrderNotExist(fmt.Errorf("订单 %s 不存在", orderNo))
	}
	if order != nil && memberId != 0 && order.MemberId != memberId {
		return nil, lueerror.OrderNotExist(fmt.Errorf("订单 %s 不存在", orderNo))
	}
	return order, nil
}

// GetRechargeOrderByOrderNo 根据单号获取订单详情
func (srv *assetSrv) GetRechargeOrderByOrderNo(ctx context.Context, memberId int64, orderNo string) (*pb.RechargeOrderReply, lueerror.LueError) {
	order, errL := srv.getRechargeOrderByOrderNo(ctx, memberId, orderNo, true, false)
	if errL != nil {
		return nil, errL
	}
	return srv.toRechargeOrderReply(order), nil
}

// CreatePayOrderForRechargeOrder 创建充值订单的支付单
func (srv *assetSrv) CreatePayOrderForRechargeOrder(ctx context.Context, appId, openId string, p *pb.PrepayInfoReq) (*pb.PrePayInfoReply, lueerror.LueError) {
	if p == nil {
		return nil, nil
	}
	// 获取订单
	order, errL := srv.getRechargeOrderByOrderNo(ctx, 0, p.OrderNo, false, false)
	if errL != nil {
		return nil, errL
	}
	if !order.CanBePayed() {
		return nil, lueerror.OrderCantBePayed(errors.New("订单不在可支付状态"))
	}
	// 支付单请求参数整理
	payOrderReq := &object.CreatePayOrderInfo{
		OrderKey:  strconv.FormatInt(order.MemberId, 10),
		BrandId:   order.BrandId,
		AppId:     appId,
		OpenId:    openId,
		StoreId:   order.StoreId,
		BizNo:     order.OrderNo,
		Amount:    order.Amount,
		Remark:    p.Remark,
		IsvAppId:  p.IsvAppId,
		IsvOpenId: p.IsvOpenId,
		CardInfo: &object.CardInfo{
			BrandId:  order.BrandId,
			MemberId: order.MemberId,
			CardId:   order.CardId,
			AccId:    order.AccId,
		},
	}
	if err := payOrderReq.SetBilinApp(order.OrderSource); err != nil {
		return nil, lueerror.OrderCantBePayed(fmt.Errorf("订单来源 %s 不支持", order.OrderSource))
	}
	prepayInfo, err := dao.GetOrdersDao().CreatePayOrder(ctx, payOrderReq)
	if err != nil {
		if errors.Is(err, model.InvalidOrderSorceType) {
			return nil, lueerror.OrderCantBePayed(fmt.Errorf("订单来源 %s 不支持", order.OrderSource))
		}
		if errors.Is(err, model.PayOrderCantBePayed) {
			return nil, lueerror.OrderCantBePayed(fmt.Errorf("支付当状态不可以支付"))
		}
		return nil, lueerror.BilinPayErr(err)
	}
	// 更新支付单号
	order.PayOrderCreated(prepayInfo.PayOrderNo)
	err = dao.GetOrdersDao().UpdatePayOrderNoById(ctx, order)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return &pb.PrePayInfoReply{
		PayOrderNo:  prepayInfo.PayOrderNo,
		PrepayInfo:  string(prepayInfo.PrepayInfo),
		PayTypeName: prepayInfo.PayTypeName,
	}, nil
}

func (srv *assetSrv) updateRechargeOrderByPayOrder(ctx context.Context, payOrder *object.PayOrderDetail) (*model.RechargeOrder, lueerror.LueError) {
	if payOrder == nil {
		return nil, nil
	}
	ret, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		// 锁定支付单
		order, errL := srv.getRechargeOrderByOrderNo(ctx, 0, payOrder.BizNo, false, true)
		if errL != nil {
			return nil, errL
		}
		// 无状态变更
		if order.Status == payOrder.ToRechargeOrderStatus() {
			return order, nil
		}
		if order.IsFinished() {
			return nil, lueerror.OrderIsFinished(fmt.Errorf("订单 %s 状态为 %s", order.OrderNo, order.GetStatus()))
		}
		// 更新订单
		err := order.UpdatePayStatus(payOrder.ToRechargeOrderStatus(), payOrder.UserPayed, payOrder.PayOrderNo, payOrder.PayTime)
		if err != nil {
			return nil, lueerror.InvalidStatus(err)
		}
		err = dao.GetOrdersDao().UpdateRechargeOrderById(ctx, order)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		// 添加余额变动流水
		if order.IsPayed() {
			errL = srv.addBalanceLogByRechargeOrder(ctx, order)
			if errL != nil {
				return nil, errL
			}
		}
		return order, nil
	})
	if err != nil {
		return nil, parseLueerror(err)
	}
	return ret.(*model.RechargeOrder), nil
}

// TriggerPayOrderSuccess 前端触发支付订单已经支付成功
func (srv *assetSrv) TriggerPayOrderSuccess(ctx context.Context, payOrderNo string) lueerror.LueError {
	payOrder, err := dao.GetOrdersDao().TriggerPayOrderSuccess(ctx, payOrderNo)
	if err != nil {
		return lueerror.BilinPayErr(err)
	}
	order, errL := srv.updateRechargeOrderByPayOrder(ctx, payOrder)
	if errL != nil {
		return errL
	}
	// 如果订单未检测到支付成功，加入定时任务轮询
	if order.Status == model.RechargeOrderPaying {
		sch := model.NewRechargeSchedule(order.Id, model.SchOpRecharge)
		_, err = dao.GetScheduleDao().CreateSchedule(ctx, sch)
		if err != nil {
			return lueerror.DbErr(err)
		}
	}
	return nil
}

// CancelPayOrder 取消支付
func (srv *assetSrv) CancelPayOrder(ctx context.Context, payOrderNo string) lueerror.LueError {
	_, err := dao.GetOrdersDao().CancelPayOrder(ctx, payOrderNo)
	if err != nil {
		return lueerror.BilinPayErr(err)
	}
	return nil
}

// RechargeOrderPayedNotify 充值单支付成功通知
func (srv *assetSrv) RechargeOrderPayedNotify(ctx context.Context, p *object.PayOrderDetail) lueerror.LueError {
	if p == nil {
		return nil
	}
	if !p.IsPaySuccess() {
		return nil
	}
	_, errL := srv.updateRechargeOrderByPayOrder(ctx, p)
	return errL
}
